"use strict";

var sys=require('sys');
var yaml=require('yaml');
var fs=require('fs');
var log=require('logging');
var eyes=require('eyes');

var object=require("./object");
var scope=require("./scope");
var util=require("./util");
var method=require("./method");
var channel=require("./channel");

var system=JSON.parse(fs.readFileSync('system.json').toString());
var test=JSON.parse(fs.readFileSync('sicp.json').toString());
system.test=test;

var t=scope.treeToScope(system);

var key;
var unitTest;

for(key in system.test)
{
  if(system.test.hasOwnProperty(key))
  {
    unitTest=system.test[key];

    sys.puts(formatMethod(key, unitTest, system, ''));
  }
}

function formatMethod(fname, f, scope, indent)
{
  var typ=f.type;
  var s='';

  if(typ=='method')
  {
    s=s+indent+fname+'('+formatParams(f.params)+'):'+"\n";
    s=s+formatPrivate(f, scope, indent);
    s=s+formatCode(f.code, scope, indent+'  ');
  }

//  if(s.substring(s.length-2,s.length)=="\n\n")
//  {
//    s=s.substring(0,s.length-1);
//  }

  return s;
}

function formatParams(params)
{
  var param;
  var s='';

  if(params.length==0)
  {
    return '';
  }

  for(param in params)
  {
    param=params[param];
    s=s+param+', ';
  }

  return s.substring(0,s.length-2);
}

function formatPrivate(f, t, indent)
{
  var pf;
  var s='';

  for(pf in f)
  {
    if(f.hasOwnProperty(pf))
    {
      if(pf!=='type' && pf!=='params' && pf!=='code')
      {
        s=s+indent+formatMethod(pf, f[pf], t, indent+'  ')+"\n";
      }
    }
  }

  return s;
}

function formatArgs(args, scope, indent)
{
  var param;
  var s='';
  var value;

  if(args.length==0)
  {
    return '';
  }

  for(param in args)
  {
    value=args[param];
    s=s+formatArg(value, scope, indent)+', ';
  }

  return s.substring(0,s.length-2);
}

function formatFunc(code, scope)
{
  var name=code[1][0]
  var args=code[1][1]
  var f;
  var l=[];

  if(hasView(scope, name))
  {
    f=scope[name];
    return formatView(f.view, args, scope);
  }
  else
  {
    return [{line: name+'('+formatArgs(args, scope)+')', children: null}];
  }
}

function hasBlock(view)
{
  var item;
  var value;

  for(item in view)
  {
    value=view[item];
    if(value[0]=='block')
    {
      return true;
    }
  }

  return false;
}

function formatCode(code, scope, indent)
{
//  log('formatCode:', code);

  var s='';
  var typ=code[0];
  var name;
  var args;
  var f;
  var list;
  var item;
  var value;

  if(typ=='func')
  {
    list=formatFunc(code, scope);
  }

  s=formatTree(list, indent);

//  log('formatCode:', s+'.');

  return s;
}

function hasView(scope, name)
{
  var f;

  if(scope.hasOwnProperty(name))
  {
    f=scope[name];
    if(f.hasOwnProperty('view'))
    {
      return true;
    }
  }

  return false;
}

function formatView(view, args, scope)
{
  var item;
  var value;

//  log('view: ', view);

  if(args.length==0)
  {
    return [];
  }

  if(hasBlock(view))
  {
    return formatBlockView(view, args, scope);
  }
  else
  {
    return formatInlineView(view, args, scope);
  }
}

function formatInlineView(view, args, scope)
{
//  log('formatInlineView:', view, indent.length);

  var value;
  var index;
  var item;
  var s='';

  for(item in view)
  {
    value=view[item];

    if(value[0]=='func')
    {
      s=s+value[1];
    }
    else if(value[0]=='symref')
    {
      index=value[1];
      value=args[index];
      s=s+formatArg(value, scope);
    }
    else if(value[0]=='sugar')
    {
      s=s+value[1];
    }

    s=s+' ';
  }

  return [{line: s.substring(0,s.length-1), children: null}];
}

function formatBlockView(view, args, scope)
{
//  log('formatBlockView:', view, indent.length);

  var index;
  var item;
  var value;
  var lines=[];
  var current={line: '', children: null};

  for(item in view)
  {
    value=view[item];

    if(value[0]=='func')
    {
      current.line=current.line+value[1]+" ";
    }
    else if(value[0]=='sugar')
    {
      current.line=current.line+value[1]+" ";
    }
    else if(value[0]=='symref')
    {
      index=value[1];
      value=args[index];
      current.line=current.line+formatArg(value, scope)+" ";
    }
    else if(value[0]=='block')
    {
      index=value[1];
      value=args[index][1].code;
      current.children=formatFunc(value, scope);
      lines.push(current);
      current={line: '', children: null};
    }
  }

  if(current.line!='' || current.children!=null)
  {
    lines.push(current);
  }

  return lines;
}

function formatArg(arg, scope)
{
  if(arg[0]=='literal')
  {
    if(util.typeOf(arg[1])=='string')
    {
      return "'"+arg[1]+"'";
    }
    else
    {
      return arg[1];
    }
  }
  else if(arg[0]=='func')
  {
    return formatFunc(arg, scope)[0].line;
  }
  else if(arg[0]=='symref')
  {
    return arg[1];
  }
}

function formatTree(list, indent)
{
  var s='';
  var item;
  var tree;

  for(item in list)
  {
    tree=list[item];

    s=s+indent+tree.line+"\n";
    if(tree.children!==null)
    {
      s=s+formatTree(tree.children, indent+'  ');
    }
  }

  return s;
}
